package persist

import (
	"fmt"
	"gitee.com/git_public/vfaith/builtin/vault"
	"gitee.com/git_public/vfaith/sugar"
	"github.com/jmoiron/sqlx"
	"log"
	"strings"
)

type OexSqlxAlpha struct {
	conn *Connect
	*SqlxDriver
}

func (oex *OexSqlxAlpha) InitOpsExt(conn *Connect, driver IxDriver) {
	oex.conn = conn
	oex.SqlxDriver = driver.(*SqlxDriver)
}

// region 自定义方法封装

func (oex *OexSqlxAlpha) QueryNum(query string, param *vault.QueryParam, argsTx ...*sqlx.Tx) (int, error) {

	query = oex.buildWhereClause(query, param.SqlCondition())
	args := param.SqlCondition().Args

	// 获取总记录数
	var totalRecord int
	var err error

	if tx := GetDefaultTx(argsTx); tx != nil {
		if err = tx.QueryRow(query, args...).Scan(&totalRecord); err != nil {
			_ = tx.Rollback()
		}
	} else {
		err = oex.QueryRow(query, args...).Scan(&totalRecord)
	}

	if err != nil {
		log.Printf("Count数据失败，异常原因：【%s】", err)
		return 0, err
	}

	param.SetTotalNum(totalRecord)

	return totalRecord, nil
}

func (oex *OexSqlxAlpha) QueryList(dest interface{}, query string, param *vault.QueryParam, argsTx ...*sqlx.Tx) error {
	query = oex.buildQuery(query, param)
	args := param.SqlCondition().Args

	var err error

	if tx := GetDefaultTx(argsTx); tx != nil {
		if err = tx.Select(dest, query, args...); err != nil {
			_ = tx.Rollback()
		}
	} else {
		err = oex.Select(dest, query, args...)
	}

	if err != nil {
		log.Printf("Select数据失败，异常原因：【%s】", err)
		return err
	}

	return nil
}

func (oex *OexSqlxAlpha) ScanToMap(query string, paramX ...*vault.QueryParam) (*vault.TableMap, error) {
	param := sugar.GetDefaultArgs(paramX, func() *vault.QueryParam {
		return vault.NewQueryParam(false)
	})

	if param == nil {
		param = vault.NewQueryParam(false)
	}

	query = oex.buildQuery(query, param)

	rows, err := oex.Queryx(query, param.SqlCondition().Args...)
	if err != nil {
		return &vault.TableMap{}, err
	}
	defer func(rows *sqlx.Rows) {
		err1 := rows.Close()
		if err1 != nil {
			log.Println(err1)
		}
	}(rows)

	columnTypes, _ := rows.ColumnTypes()
	var header []vault.TableHeader
	for _, item := range columnTypes {
		header = append(header, *vault.NewTableHeader(item))
	}

	// 遍历初始集合并构建新的集合
	columns, _ := rows.Columns()
	tableRows := make([]vault.TableRow, 0)
	for rows.Next() {
		values := make([]interface{}, len(columns))
		valuePtrs := make([]interface{}, len(columns))

		for i := range columns {
			valuePtrs[i] = &values[i]
		}

		if err1 := rows.Scan(valuePtrs...); err1 != nil {
			return &vault.TableMap{}, err1
		}

		rowMap := make(map[string]interface{})
		for i, col := range columns {
			val := values[i]

			// 处理SQL驱动返回的[]byte类型
			if b, ok := val.([]byte); ok {
				rowMap[col] = string(b)
			} else {
				rowMap[col] = val
			}
		}

		tableRows = append(tableRows, rowMap)
	}

	if err2 := rows.Err(); err2 != nil {
		return &vault.TableMap{}, err2
	}

	return vault.NewTableMap(header, tableRows), nil
}

// endregion

// region 动态生成公共类

// 拼装SQL语句
func (oex *OexSqlxAlpha) buildQuery(query string, param *vault.QueryParam) string {

	query = oex.buildWhereClause(query, param.SqlCondition())

	if param.OrderBy() != "" {
		query += " order by " + param.OrderBy()
	}

	// 分页
	if param.PageCondition != nil && param.PageNow > 0 && param.PageLimit > 0 {
		offset := (param.PageNow - 1) * param.PageLimit
		query += fmt.Sprintf(" limit %d offset %d", param.PageLimit, offset)
	}
	log.Print("**********************************************")
	log.Printf("Generate Sql 【%s】", query)
	log.Print("**********************************************")

	return query
}

// 拼装where子句
func (oex *OexSqlxAlpha) buildWhereClause(query string, sc *vault.SqlCondition) string {

	if sc != nil && sc.Conditions != nil {
		queryWhere := " where 1 = 1 " + strings.Join(sc.Conditions, " ")
		if strings.Index(strings.Replace(query, " ", "", -1), "where1=1") > -1 {
			query = strings.Replace(query, "where 1 = 1", queryWhere, -1)
		} else {
			query += queryWhere
		}
	}

	return query
}

// endregion
